﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Routing;
using EPiAbstractions.Common.Attributes;
using EPiServer.Common;
using EPiServer.Common.Attributes;
using EPiServer.Common.Categories;
using EPiServer.Common.Comments;
using EPiServer.Common.Sorting;
using EPiServer.Common.Tags;
using EPiServer.Community.Blog;
using JoelAbrahamsson.WebUtilities;
using StructureMap;
using Attribute=EPiServer.Common.Attributes.Attribute;

namespace JoelAbrahamsson.BlogExtensions
{
    public static class EntryExtensions
    {
        public const string SLUG_ATTRIBUTE_NAME = "BlogEntrySlug";
        public const string EXCERPT_ATTRIBUTE_NAME = "BlogEntryExcerpt";
        public const string COMMENTS_SUBSCRIBERS_ATTRIBUTE_NAME = "EntryCommentsSubscribers";
        public const string OLD_URLS_ATTRIBUTE_NAME = "OldUrls";

        public static string GetUrl(this Entry entry, RequestContext context)
        {
            return "http://"
                + System.Configuration.ConfigurationManager.AppSettings["defaultDomain"]
                + RouteTable.Routes.GetVirtualPath(context, "Entry", new RouteValueDictionary(new { slug = entry.GetSlug(), action = "Index" })).VirtualPath;
        }

        public static void SetSlug(this Entry entry, string slug)
        {
            EnsureAttributeExists<Entry, string>(SLUG_ATTRIBUTE_NAME);

            entry.SetAttributeValue(SLUG_ATTRIBUTE_NAME, slug);
        }

        public static string GetSlug(this Entry entry)
        {
            EnsureAttributeExists<Entry, string>(SLUG_ATTRIBUTE_NAME);

            return entry.GetAttributeValue<string>(SLUG_ATTRIBUTE_NAME);
        }

        public static void SetExcerpt(this Entry entry, string excerpt)
        {
            EnsureAttributeExists<Entry, string>(EXCERPT_ATTRIBUTE_NAME);

            entry.SetAttributeValue(EXCERPT_ATTRIBUTE_NAME, excerpt);
        }

        public static string GetExcerpt(this Entry entry)
        {
            EnsureAttributeExists<Entry, string>(EXCERPT_ATTRIBUTE_NAME);

            return entry.GetAttributeValue<string>(EXCERPT_ATTRIBUTE_NAME);
        }

        private static void EnsureAttributeExists<TEntity, TAttribute>(string attributeName)
        {
            if (AttributeHandlerFacade.Instance.GetAttributes(typeof(TEntity)).Count(existingsAttribute => IsMatchingAttribute<TAttribute>(existingsAttribute, attributeName)) > 0)
                return;

            Attribute attribute = new Attribute(attributeName, typeof(TEntity), typeof(TAttribute), false);

            AttributeHandlerFacade.Instance.AddAttribute(attribute);
        }

        private static bool IsMatchingAttribute<TAttribute>(IAttribute existingsAttribute, string attributeName)
        {
            return existingsAttribute.Name == attributeName && existingsAttribute.DataType.Type == typeof(TAttribute);
        }

        public static string GetTeaserText(this Entry entry)
        {
            string teaser = entry.GetExcerpt();
            if (string.IsNullOrEmpty(teaser))
                teaser = HtmlUtility.RemoveHtml(entry.Content).EllipseText(300);

            return teaser;
        }

        public static IList<IAuthor> GetSubscribers(this Entry entry)
        {
            EnsureAttributeExists<Entry, IAuthor>(COMMENTS_SUBSCRIBERS_ATTRIBUTE_NAME);
            return entry.GetAttributeValues<IAuthor>(COMMENTS_SUBSCRIBERS_ATTRIBUTE_NAME);
        }

        public static void AddSubscriber(this Entry entry, IAuthor subscriber)
        {
            EnsureAttributeExists<Entry, IAuthor>(COMMENTS_SUBSCRIBERS_ATTRIBUTE_NAME);
            IList<IAuthor> subscribers = entry.GetSubscribers();
            subscribers.Add(subscriber);
            subscribers = subscribers.Where(s => s != null).ToList();
            entry.SetAttributeValue<IAuthor>(COMMENTS_SUBSCRIBERS_ATTRIBUTE_NAME, subscribers);
        }

        public static IList<string> GetOldUrls(this Entry entry)
        {
            EnsureAttributeExists<Entry, string>(OLD_URLS_ATTRIBUTE_NAME);
            return entry.GetAttributeValues<string>(OLD_URLS_ATTRIBUTE_NAME);
        }

        public static void AddOldUrl(this Entry entry, string url)
        {
            EnsureAttributeExists<Entry, string>(OLD_URLS_ATTRIBUTE_NAME);
            IList<string> oldUrls = entry.GetAttributeValues<string>(OLD_URLS_ATTRIBUTE_NAME);
            oldUrls.Add(url);
            entry.SetAttributeValue(OLD_URLS_ATTRIBUTE_NAME, oldUrls);
        }

        public static CommentCollection GetLatestComments(this Entry entry, int pageSize)
        {
            int totalItems;
            return CommentHandler.GetComments(entry, 1, pageSize, out totalItems, new CommentSortOrder(CommentSortField.Created, SortingDirection.Ascending));   
        }

        public static IEnumerable<ICategory> GetBlogCategories(this Entry entry)
        {
            return entry.Categories.Where(category => 
                category.Parent != null 
                && category.Parent.Parent != null 
                && category.Parent.Parent.ID == ObjectFactory.GetInstance<BlogCategoryProvider>().BlogCategoriesRoot.ID);
        }

        public static DateTime GetPublicationDate(this Entry entry)
        {
            if (entry.PublicationStart <= default(DateTime))
                return entry.Created;

            return entry.PublicationStart;
        }

        public static string GetMetaKeywordsString(this Entry entry)
        {
            if (entry.Tags.Count == 0)
                return string.Empty;

            StringBuilder result = new StringBuilder();
            foreach (ITag tag in entry.Tags)
            {
                result.Append(tag.Name);
                result.Append(", ");
            }
            result.Remove(result.Length - 2, 2);

            return result.ToString();
        }
    }
}
